import { Component, Vue, Prop, PropSync, Watch } from 'vue-property-decorator'
import Styles from './styles.less'

@Component({})
export default class PreviewImages extends Vue {
  @Prop({ default: [] }) private list!: any[]
  @Prop({ default: 0 }) private index!: number
  @Prop({ default: false }) private closeWithBackdrop!: boolean
  @PropSync('show', { default: false }) private syncShow!: boolean

  private currentIndex: number = -1
  private positionInfo: any | any[] = []
  private isDisabled: boolean = false
  private mousedownInfo: any = null
  private timer: any = null

  protected render(h: any) {
    return (
      <section
        class={[Styles.vcPreviewImages, { [Styles.show]: this.syncShow }]}
        onMousedown={this.mousedownEvt}
        onMouseup={this.mouseupEvt}
      >
        <i class="close-icon el-icon-close" onClick={this.closeEvt} />
        <ul class="imgs-list">
          {this.list.map((url: string, i: number) => {
            return (
              <li v-show={this.currentIndex === i} key={url}>
                <figure ref={`figure${i}`}>
                  <img
                    url={url}
                    ref={`img${i}`}
                    onload={(e: Event) => this.loadEvt(e, i, url)}
                  />
                </figure>
                <i class="el-icon-loading" />
              </li>
            )
          })}
        </ul>
        <div class="setting-box">
          <span
            class={['zoom-out', { disabled: this.isDisabled }]}
            onClick={() => this.zoomEvt(-0.1)}
          >
            <i class="el-icon-zoom-out" />
          </span>
          <span class="zoom-in" onClick={() => this.zoomEvt(0.1)}>
            <i class="el-icon-zoom-in" />
          </span>
          {this.$slots.default}
        </div>
      </section>
    )
  }

  @Watch('list')
  private listWatch(val: any) {
    this.currentIndex = -1
  }

  @Watch('show')
  private showWatch(val: boolean) {
    if (val && this.currentIndex === -1) {
      this.currentIndex = this.index
    }
  }

  @Watch('currentIndex')
  private currentIndexWatch(val: number) {
    const imgEl: any = this.$refs[`img${val}`]

    if (imgEl && imgEl.hasAttribute('url')) {
      imgEl.src = imgEl.getAttribute('url')
    }
  }

  private mounted() {
    document.addEventListener('mousemove', this.moveEvt)
  }

  private loadEvt(evt: any, index: number, url: string) {
    const imgEl = evt.target
    // 获取图片的大小信息
    const { naturalWidth: width, naturalHeight: height } = evt.target
    // 获取窗口大小
    const { innerWidth, innerHeight } = window
    let w = width
    let h = height
    let x = 0
    let y = 0
    const perW = width / innerWidth
    const perH = height / innerHeight

    if (perW > perH) {
      if (perW > 1) {
        w = innerWidth
        h = parseInt(String(height / perW))
      }
    } else {
      if (perH > 1) {
        h = innerHeight
        w = parseInt(String(width / perH))
      }
    }

    x = parseInt(String((innerWidth - w) / 2))
    y = parseInt(String((innerHeight - h) / 2))

    this.positionInfo[index] = { w, h, x, y, scale: 1, loaded: true }

    imgEl.removeAttribute('url')
    imgEl.setAttribute('loaded', '')
    imgEl.parentNode.setAttribute('loaded', '')

    this.setImgStyle(index)
  }

  private errorEvt(url: string) {
    this.$emit('error', url)
  }

  private closeEvt() {
    this.$emit('update:show', false)
  }

  private setImgStyle(index: number, hasAnimate: boolean = false) {
    const style: any = this.positionInfo[index]

    if (style) {
      const { w, h, x, y, scale } = style
      const imgs: any = this.$refs[`figure${index}`]
      const setStyle: any = {
        width: `${w}px`,
        height: `${h}px`,
        opacity: 1,
        transform: `translate(${x}px, ${y}px) scale(${scale})`,
      }

      if (hasAnimate) setStyle.transition = 'transform .3s ease-out'
      else setStyle.transition = 'transform 0s ease-out'

      Object.assign(imgs.style, setStyle)

      this.updateIsDisabled()
    }
  }

  private goto(step: number) {
    if (step > 0) {
      if (this.currentIndex < this.list.length - 1) {
        this.currentIndex++
      } else {
        this.currentIndex = 0
      }
    } else {
      if (this.currentIndex === 0) {
        this.currentIndex = this.list.length - 1
      } else {
        this.currentIndex--
      }
    }

    this.updateIsDisabled()
  }

  private zoomEvt(step: number) {
    const { scale } = this.positionInfo[this.currentIndex]
    // 缩小最大为0.1，防止图片不可见
    if (step < 0 && scale === 0.1) return

    this.positionInfo[this.currentIndex].scale = Number(
      (scale + step).toFixed(1)
    )

    this.setImgStyle(this.currentIndex, true)
  }

  private updateIsDisabled() {
    if (this.positionInfo[this.currentIndex]) {
      this.isDisabled = this.positionInfo[this.currentIndex].scale === 0.1
    }
  }

  private moveEvt(evt: any) {
    if (this.timer) clearTimeout(this.timer)

    if (this.mousedownInfo) {
      const { pageX, pageY } = this.mousedownInfo
      const { ix, iy } = this.positionInfo[this.currentIndex]
      const x = ix + evt.pageX - pageX
      const y = iy + evt.pageY - pageY

      this.positionInfo[this.currentIndex] = Object.assign(
        {},
        this.positionInfo[this.currentIndex],
        { x, y }
      )
      this.setImgStyle(this.currentIndex)
    }
  }

  private mousedownEvt(evt: any) {
    const info = this.positionInfo[this.currentIndex]

    if (info && info.loaded) {
      const { x, y } = info

      this.positionInfo[this.currentIndex].ix = x
      this.positionInfo[this.currentIndex].iy = y
      this.mousedownInfo = evt
    }

    // 点击背景时关闭弹层
    if (this.closeWithBackdrop && evt.target.tagName === 'LI') {
      this.timer = setTimeout(this.closeEvt, 100)
    }
  }

  private mouseupEvt() {
    this.mousedownInfo = null
  }

  private beforeDestroy() {
    document.removeEventListener('mousemove', this.moveEvt)
  }
}
